// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Text; using System.Xml.Linq; using JetBrains.Annotations; namespace LargoCommon.Music { /// /// Harmonic Motive. /// [Serializable] public sealed class RhythmicMotive { #region Fields /// /// Element schema. /// private string elementSchema; /// /// Mean Mobility. /// private float? meanMobility; /// /// Mean Variance. /// private float? meanVariance; /// /// Unique identifier. /// private string uniqueIdentifier; /// /// Melodic Structures. /// [NonSerialized] private IEnumerable rhythmicStructures; #endregion #region Constructors /// /// Initializes a new instance of the class. /// public RhythmicMotive() { this.RhythmicStructures = new List(); } /// /// Initializes a new instance of the RhythmicMotive class. /// /// Name of the motive. /// Rhythmical structures. public RhythmicMotive(string name, IEnumerable rhythmicStructures) //// RhythmicCore core, : this() { if (rhythmicStructures == null) { return; } this.Name = name; //// 2014/12 Time optimization ... int barNumber = 1; foreach (var rstruct in rhythmicStructures) { if (rstruct == null) { continue; } //// 2014/12 Time optimization //// rstruct.BarNumber = barNumber++; this.AddStructure(rstruct); //// 1, RhythmicStructures.Count() } } #endregion #region Properties - Xml /// Gets Xml representation. /// Property description. public XElement GetXElement { get { var xe = new XElement( "Motive", new XAttribute("Length", this.Length)); var xstructs = new XElement("Structures"); foreach (var rstruct in this.RhythmicStructures) { var xstruct = rstruct.GetXElement; xstructs.Add(xstruct); } xe.Add(xstructs); return xe; } } #endregion #region Properties /// /// Gets or sets the name. /// /// /// Property description. /// [UsedImplicitly] public string Shortcut { get; set; } //// CA1044 (FxCop) /// /// Gets or sets the full name. /// /// /// The full name. /// [UsedImplicitly] public string Name { get; set; } //// CA1044 (FxCop) /// /// Gets or sets the number. /// /// /// Property description. /// public int Number { get; set; } /// /// Gets or sets the first bar number. /// /// /// The first bar number. /// public int FirstBarNumber { get; set; } /// /// Gets or sets the occurrence. /// /// /// The occurrence. /// public int Occurrence { get; set; } /// /// Gets or sets the rhythmic structures. /// /// /// The rhythmic structures. /// public IEnumerable RhythmicStructures { get { Contract.Ensures(Contract.Result>() != null); if (this.rhythmicStructures == null) { throw new InvalidOperationException("Rhythmic structures are null."); } return this.rhythmicStructures; } set => this.rhythmicStructures = value ?? throw new ArgumentException("Rhythmic structures cannot be empty.", nameof(value)); } /// /// Gets the length. /// /// Property description. public int Length => ((List)this.RhythmicStructures).Count; /// Gets list of all already defined tones. /// Property description. public string UniqueIdentifier { get { if (this.uniqueIdentifier != null) { return this.uniqueIdentifier; } var ident = new StringBuilder(); var rhythmicMotiveStructureList = this.RhythmicStructures.ToList(); ident.Append(string.Format(CultureInfo.CurrentCulture, "#{0}#", rhythmicMotiveStructureList.Count)); //// ident.Append(rms.StructuralCode); //// .ToString(CultureInfo.CurrentCulture)//// ElementSchema, TRhythmicStructure.ElementSchema //// ElementSchema, DecimalNumber, ms.StructuralCode foreach (var b in from rms in rhythmicMotiveStructureList where rms?.GetStructuralCode != null from b in rms.GetStructuralCode select b) { ident.Append(b); } this.uniqueIdentifier = ident.ToString(); return this.uniqueIdentifier; } } /// Gets list of all already defined tones. /// Property description. [UsedImplicitly] public string ElementSchema { get { if (this.elementSchema != null) { return this.elementSchema; } var elemSchema = new StringBuilder(); foreach (var rms in this.RhythmicStructures) { elemSchema.Append(rms.ElementSchema.ToString(CultureInfo.CurrentCulture)); //// ElementSchema, TRhythmicStructure.ElementSchema elemSchema.Append("/"); } this.elementSchema = elemSchema.ToString(); return this.elementSchema; } } #endregion #region Physical properties /// Gets list of all already defined tones. /// Property description. [UsedImplicitly] public float MeanMobility { get { var cnt = this.RhythmicStructures.Count(); if (this.meanMobility != null || cnt <= 0) { return this.meanMobility ?? 0; } var totalMobility = this.RhythmicStructures.Sum(rms => rms.RhythmicBehavior.Mobility); this.meanMobility = totalMobility / cnt; return (float)this.meanMobility; } } /// Gets list of all already defined tones. /// Property description. [UsedImplicitly] public float MeanVariance { get { var cnt = this.RhythmicStructures.Count(); if (this.meanVariance != null || cnt <= 0) { return this.meanVariance ?? 0; } var totalVariance = this.RhythmicStructures.Sum(rms => rms.FormalBehavior.Variance); this.meanVariance = totalVariance / cnt; return (float)this.meanVariance; } } #endregion #region Static Factory methods /// /// Simple RhythmicMotive. /// /// Rhythmical structure. /// Returns value. [UsedImplicitly] public static RhythmicMotive SimpleRhythmicMotive(RhythmicStructure rhythmicStruct) { if (rhythmicStruct == null) { return null; } var rm = new RhythmicMotive(); //// 2014/12 Time optimization //// rhythmicStruct.BarNumber = 1; rm.AddStructure(rhythmicStruct); return rm; } /// /// Simple Rhythmic Motive. /// /// Rhythmical order. /// The structural code. /// /// Returns value. /// [UsedImplicitly] public static RhythmicMotive SimpleRhythmicMotive(byte rhythmicOrder, string structuralCode) { //// bool rhythmical, int barNumber, var rm = new RhythmicMotive(); var rs = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, rhythmicOrder); for (var ib = 0; ib < 4; ib++) { //// 2014/12 Time optimization //// rstruct.BarNumber = barNumber + ib var rstruct = new RhythmicStructure(rs, structuralCode); rm.AddStructure(rstruct); } return rm; } #endregion #region Public methods /// /// Converts to order. /// /// The given system. public void ConvertToSystem(RhythmicSystem givenSystem) { var cnt = this.RhythmicStructures.Count(); if (cnt == 0) { return; } var newStructures = this.RhythmicStructures.Select(s => s.ConvertToSystem(givenSystem)).ToList(); this.RhythmicStructures = newStructures; } /// Returns value of characteristic planned for given musical bar. /// Number of musical bar. /// Returns value. public string RhythmicStructuralCodeForBar(int barNumber) { var structure = this.RhythmicStructureInBarNumber(barNumber); return structure?.GetStructuralCode; } /// /// Adds the structure. /// /// The structure. public void AddStructure(RhythmicStructure structure) { ((List)this.RhythmicStructures).Add(structure); } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// [UsedImplicitly] public override string ToString() { return this.Name; } #endregion #region Private methods /// /// Rhythmic structure in bar. /// /// The bar number. /// Returns value. private RhythmicStructure RhythmicStructureInBarNumber(int barNumber) { if (barNumber < 1) { throw new ArgumentOutOfRangeException(nameof(barNumber), "value must be positive"); } var cnt = this.RhythmicStructures.Count(); if (cnt == 0) { return null; //// throw new ArgumentException("No rhythmic motive structure!"); } var idx = (barNumber - 1) % cnt; var structure = this.RhythmicStructures.ElementAt(idx); return structure; } #endregion } }